function Base64() {

    // private property
    _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    // public method for encoding
    this.encode = function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        input = _utf8_encode(input);
        while (i < input.length) {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;
            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }
            output = output +
                _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
                _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
        }
        return output;
    }

    // public method for decoding
    this.decode = function (input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
        while (i < input.length) {
            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));
            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            output = output + String.fromCharCode(chr1);
            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }
        }
        output = _utf8_decode(output);
        return output;
    }

    // private method for UTF-8 encoding
    _utf8_encode = function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }
        return utftext;
    }

    // private method for UTF-8 decoding
    _utf8_decode = function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;
        while ( i < utftext.length ) {
            c = utftext.charCodeAt(i);
            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            } else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            } else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }
        return string;
    }
}
/*
 * MAP对象，实现MAP功能
 *
 * 接口：
 * size()     获取MAP元素个数
 * isEmpty()    判断MAP是否为空
 * clear()     删除MAP所有元素
 * put(key, value)   向MAP中增加元素（key, value)
 * remove(key)    删除指定KEY的元素，成功返回True，失败返回False
 * get(key)    获取指定KEY的元素值VALUE，失败返回NULL
 * element(index)   获取指定索引的元素（使用element.key，element.value获取KEY和VALUE），失败返回NULL
 * containsKey(key)  判断MAP中是否含有指定KEY的元素
 * containsValue(value) 判断MAP中是否含有指定VALUE的元素
 * values()    获取MAP中所有VALUE的数组（ARRAY）
 * keys()     获取MAP中所有KEY的数组（ARRAY）
 *
 * 例子：
 * var map = new Map();
 *
 * map.put("key", "value");
 * var val = map.get("key")
 * ……
 *
 */
function Map() {
    this.elements = new Array();

    //使用数组初始化Map
    this.putAll = function(eles) {
        this.elements = eles;
    };

    //取所有元素
    this.getAll = function() {
        return this.elements;
    }

    //获取MAP元素个数
    this.size = function() {
        return this.elements.length;
    };

    //判断MAP是否为空
    this.isEmpty = function() {
        return (this.elements.length < 1);
    };
    //删除MAP所有元素
    this.clear = function() {
        this.elements = new Array();
    };
    //向MAP中增加元素（key, value)
    this.put = function(_key, _value) {
        this.elements.push( {
            key : _key,
            value : _value
        });
    };
	//方法可向数组的开头添加一个元素
    this.unshift = function(_key, _value) {
        this.elements.unshift( {
            key : _key,
            value : _value
        });
    };
    //删除指定KEY的元素，成功返回True，失败返回False
    this.remove = function(_key) {
        var bln = false;
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    this.elements.splice(i, 1);
                    return true;
                }
            }
        } catch (e) {
            bln = false;
        }
        return bln;
    };
    //获取指定KEY的元素值VALUE，失败返回NULL
    this.get = function(_key) {
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    return this.elements[i].value;
                }
            }
        } catch (e) {
            return null;
        }
    };
    //获取指定索引的元素（使用element.key，element.value获取KEY和VALUE），失败返回NULL
    this.element = function(_index) {
        if (_index < 0 || _index >= this.elements.length) {
            return null;
        }
        return this.elements[_index];
    };

    //判断MAP中是否含有指定KEY的元素
    this.containsKey = function(_key) {
        var bln = false;
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    bln = true;
                }
            }
        } catch (e) {
            bln = false;
        }
        return bln;
    };
    //判断MAP中是否含有指定VALUE的元素
    this.containsValue = function(_value) {
        var bln = false;
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].value == _value) {
                    bln = true;
                }
            }
        } catch (e) {
            bln = false;
        }
        return bln;
    };
    //获取MAP中所有VALUE的数组（ARRAY）
    this.values = function() {
        var arr = new Array();
        for (i = 0; i < this.elements.length; i++) {
            arr.push(this.elements[i].value);
        }
        return arr;
    };
    //获取MAP中所有KEY的数组（ARRAY）
    this.keys = function() {
        var arr = new Array();
        for (i = 0; i < this.elements.length; i++) {
            arr.push(this.elements[i].key);
        }
        return arr;
    };
    this.sort = function(props) {
        this.elements.sort(function(obj1, obj2){
            var lt1 = obj1.value[props];
            var lt2 = obj2.value[props];
            if (lt1 < lt2) {
                return 1;
            } else if (lt1 > lt2) {
                return -1;
            } else {
                return 0;
            }
        })
    }
}
/**
 * js实现list
 *
 */
function List() {
    this.value = [];

    this.addAll=function(all) {
        this.value = all;
    }

    /* 添加 */
    this.add = function(obj) {
        return this.value.push(obj);
    };

    /* 大小 */
    this.size = function() {
        return this.value.length;
    };

    /* 返回指定索引的值 */
    this.get = function(index) {
        return this.value[index];
    };

    /* 删除指定索引的值 */
    this.remove = function(index) {
        this.value.splice(index,1);
        return this.value;
    };

    /* 删除全部值 */
    this.removeAll = function() {
        return this.value = [];
    };

    /* 是否包含某个对象 */
    this.constains = function(obj) {
        for ( var i in this.value) {
            if (obj == this.value[i]) {
                return true;
            } else {
                continue;
            }
        }
        return false;
    };

    /* 是否包含某个对象 */
    this.getAll = function() {
        return this.value;
    };

    this.shift = function() {
        return this.shift();
    }

}
function zInit() {
    $('#doc-dropdown-js').dropdown({justify: '#doc-dropdown-justify-js'});
	$("#input_box").focus(function(){
		$('.windows_input').css('background','#fff');
		$('#input_box').css('background','#fff');
	});
	$("#input_box").blur(function(){
		$('.windows_input').css('background','');
		$('#input_box').css('background','');
	});
}
function showLoginDialog() {
	$('#dialog-login').modal({closeViaDimmer: 0});
}
var Utils = {
	stringToUint8Array:function(str){
		var bytes = new Array(); 
		var len,c;
		len = str.length;
		for(var i = 0; i < len; i++){
			c = str.charCodeAt(i);
			if(c >= 0x010000 && c <= 0x10FFFF){
				bytes.push(((c >> 18) & 0x07) | 0xF0);
				bytes.push(((c >> 12) & 0x3F) | 0x80);
				bytes.push(((c >> 6) & 0x3F) | 0x80);
				bytes.push((c & 0x3F) | 0x80);
			}else if(c >= 0x000800 && c <= 0x00FFFF){
				bytes.push(((c >> 12) & 0x0F) | 0xE0);
				bytes.push(((c >> 6) & 0x3F) | 0x80);
				bytes.push((c & 0x3F) | 0x80);
			}else if(c >= 0x000080 && c <= 0x0007FF){
				bytes.push(((c >> 6) & 0x1F) | 0xC0);
				bytes.push((c & 0x3F) | 0x80);
			}else{
				bytes.push(c & 0xFF);
			}
		}
		var tmpUint8Array = new Uint8Array(bytes);
		return tmpUint8Array;
	},
	uint8ArrayToString:function(fileData){
		var dataString = "";
		for (var i = 0; i < fileData.length; i++) {
			dataString += String.fromCharCode(fileData[i]);
		}

		return dataString;
	},
	String2Array(str) {
		return JSON.parse('[' + this.stringToUint8Array(str).toString() + ']')
	},
	objectToUint8Array:function(obj){
		return this.stringToUint8Array(JSON.stringify(obj));
	},
	uint8ArrayToObject:function(fileData){
		var str = this.uint8ArrayToString(fileData)
		return JSON.parse(str);
	},
	formatDate:function(time,format='YYYY-MM-DD hh:mm:ss'){
		var date = new Date(time);

		var year = date.getFullYear(),
			month = date.getMonth()+1,//月份是从0开始的
			day = date.getDate(),
			hour = date.getHours(),
			min = date.getMinutes(),
			sec = date.getSeconds();
		var preArr = Array.apply(null,Array(10)).map(function(elem, index) {
			return '0'+index;
		});////开个长度为10的数组 格式为 00 01 02 03

		return format.replace(/YYYY/g,year)
							.replace(/MM/g,preArr[month]||month)
							.replace(/DD/g,preArr[day]||day)
							.replace(/hh/g,preArr[hour]||hour)
							.replace(/mm/g,preArr[min]||min)
							.replace(/ss/g,preArr[sec]||sec);

	},
	getShowTime:function(time) {
		var date = new Date(time);
		var today = new Date(this.formatDate(new Date(), 'YYYY-MM-DD 00:00:00'));
		var yesterday = new Date(today - 3600);
		if (date >= today) {
			return this.formatDate(date, 'hh:mm')
		} else if (date >= yesterday && date <today) {
			return '昨天'
		} else {
			return this.formatDate(date, 'MM:DD')
		}
	},
	uuid:function() {
		var s = [];
		var hexDigits = "0123456789abcdef";
		for (var i = 0; i < 36; i++) {
			s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
		}
		s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
		s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
		s[8] = s[13] = s[18] = s[23] = "-";

		return s.join("");
	}
}
function WEBSOCKET(wsurl,vueObj){
	this._init_(wsurl,vueObj);
}
WEBSOCKET.prototype = {
	constructor:WEBSOCKET,
	_init_:function(wsurl, vueObj){
		this.vue_obj = vueObj
		var wsocket = new WebSocket(wsurl);
		console.log("connect to server:" + wsurl);
		wsocket.onopen = this.onopen;
		wsocket.onmessage = this.onmessage;
		wsocket.onerror = this.onerror;
		wsocket.onclose = this.onclose;
		wsocket.$this = this;
		this.websocket = wsocket;
	},
	writeToScreen:function(message) {
		console.log(message);
	},
	onopen:function(event) {
		this.$this.writeToScreen("connect to ws server...");
		//建立聊天会话
		this.$this.vue_obj.connection();
	},
	blobToMessage:function(data,callback) {
		var reader = new FileReader();
		reader.readAsArrayBuffer(data);
		reader.onload = function(e) {
			var buf = new Uint8Array(reader.result);
			var message = new MsgMessage({});
			message.parseByteArray(buf);
			callback(message);
		}
	},
	onmessage:function(event) {
		var _outer = this.$this;
		_outer.blobToMessage(event.data,message=>{
			
			var type = message.getType();
			if (type == "success") {
				_outer.writeToScreen("connection success！");
				_outer.vue_obj.newMsg = false;
				_outer.vue_obj.sendHistoryMessage();
			} else if( type == "message") {
				_outer.vue_obj.addMessage(message, _outer.vue_obj.newMsg);
			} else if (type == "final") {
				//同步消息结束标识消息
				if (_outer.vue_obj.syncType > _outer.vue_obj.g_group_list.size()) {
					console.log("消息同步完毕");
					//用户消息同步结束进行系统消息同步
					_outer.vue_obj.syncType = 0;
				} else {
					//同步群消息
					var groupInfo = _outer.vue_obj.g_group_list.element(_outer.vue_obj.syncType - 1).value;
					_outer.vue_obj.sendSyncMessage(groupInfo.getGroupId());
				}
			} else if (type == "ok") {
				_outer.writeToScreen("ok");
			} else if (type == "ng") {
				_outer.writeToScreen("message send error!");
				alert("消息发送失败：" + _outer.vue_obj.base64.decode(message.getContent()))
			} else if (type == "reject") {
				_outer.writeToScreen("message has been rejected! token error!");
				alert("token错误，服务端拒绝处理消息")
			} else if (type == "history-final") {
				_outer.vue_obj.newMsg = true;
				//同步消息
				_outer.vue_obj.sendSyncMessage('0');
			}
		})
		
	},
	onerror:function(event) {
		this.$this.writeToScreen("ERROR:" + event.data);
	},
	onclose:function(event){
		alert("用户可能在其他终端登录，连接断开，请重新登录")
		showLoginDialog();
	},
	doSend:function(message) {
		this.websocket.send(message);
	}
};
function MsgRequest(info) {
	this._init_(info);
}
MsgRequest.prototype = {
	constructor:MsgRequest,
	_init_:function(info) {
		this.type = info.type;
		this.user_id = info.user_id;
		this.username = info.username;
		this.password = info.password;
		this.token = info.toke;
		this.message = info.message;
		this.last_version = info.last_version;
		this.setExt(info.ext);
	},
	parseJson:function(info) {
		this._init_(info)
	},
	toByteArray:function() {
		return Utils.objectToUint8Array(this);
	},
	parseByteArray:function(data) {
		var obj = Utils.uint8ArrayToObject(data);
		this.parseJson(obj);
	},
	setExt:function(e) {
		this.ext = e;
	}
}
function MsgDevice(info) {
	this._init_(info);
}
MsgDevice.prototype = {
	constructor:MsgDevice,
	_init_:function(info) {
		this.device_id = info.device_id;
		this.device_type = info.device_type;
		this.device_brand = info.device_brand;
		this.os = info.os;
		this.os_version = info.os_version;
		this.ios_token = info.ios_token;
		this.app_ver = info.app_ver;
	},
	toByteArray:function() {
		return Utils.objectToUint8Array(this);
	},
	parseByteArray:function(data) {
		var obj = Utils.uint8ArrayToObject(data);
		this.parseJson(obj);
	},
	parseJson:function(info) {
		this._init_(info)
	},
}

function MsgResult(info) {
	this._init_(info);
}
MsgResult.prototype = {
	constructor:MsgResult,
	_init_:function(info) {
		this.status = info.status;
		this.msg = info.msg;
		this.data = info.data;
	},
	toByteArray:function() {
		return Utils.objectToUint8Array(this);
	},
	parseByteArray:function(data) {
		var obj = Utils.uint8ArrayToObject(data);
		this.parseJson(obj);
	},
	parseJson:function(info) {
		this._init_(info)
	},
	getStatus:function() {
		return this.status;
	},
	getMsg:function() {
		return this.msg;
	},
	getData:function() {
		return this.data;
	},
	getDataObj:function() {
		return JSON.parse(this.data);
	}
}

function MsgMessage(info) {
	this._init_(info);
}
MsgMessage.prototype = {
	constructor:MsgMessage,
	_init_:function(info) {
		this.type = info.type;
		this.version = info.version;
		this.time = info.time;
		this.from = info.from;
		this.to = info.to;
		this.group = info.group;
		this.content_type = info.content_type;
		this.content = info.content;
		this.attach_type = info.attach_type;
		this.attachment = info.attachment;
		this.end_time = info.end_time;
		this.token = info.token;
	},
	toByteArray:function() {
		return Utils.objectToUint8Array(this);
	},
	parseByteArray:function(data) {
		var obj = Utils.uint8ArrayToObject(data);
		this.parseJson(obj);
	},
	parseJson:function(info) {
		this._init_(info)
	},
	getType:function() {
		return this.type;
	},
	getVersion:function() {
		return this.version;
	},
	getTime:function() {
		return this.time;
	},
	getFrom:function() {
		return this.from;
	},
	getTo:function() {
		return this.to;
	},
	getGroup:function() {
		return this.group;
	},
	getContentType:function() {
		return this.content_type;
	},
	getContent:function(){
		return this.content;
	},
	getAttachType:function() {
		return this.attach_type;
	},
	getAttachment:function() {
		return this.attachment;
	},
	getEndTime:function() {
		return this.end_time;
	},
	getToken:function() {
		return this.token;
	}
}
function UserInfo(info) {
	this._init_(info);
}
UserInfo.prototype = {
	constructor:UserInfo,
	_init_:function(info) {
		this.user_id = info.user_id;
		this.username = info.username;
		this.nick_name = info.nick_name;
		this.head_img = info.head_img;
		this.address  =info.address;
		this.token = info.token;
		this.sex = info.sex;
	},
	parseJson:function(info) {
		this._init_(info)
	},
	getUserId:function() {
		return this.user_id;
	},
	getUsername:function(){
		return this.username;
	},
	getNickName:function() {
		return this.nick_name;
	},
	getHeadImg:function() {
		return this.head_img;
	},
	getAddress:function() {
		return this.address;
	},
	getToken:function() {
		return this.token;
	},
	getSex:function() {
		return this.sex;
	}
}
function LinkMan(info) {
	this._init_(info);
}
LinkMan.prototype = {
	constructor:LinkMan,
	_init_:function(info) {
		this.linkman_id = info.linkman_id;
		this.username = info.username;
		this.nick_name = info.nick_name;
		this.link_time = info.link_time;
		this.avatar = info.avatar;
		this.sex = info.sex;
		this.linkman_alias = info.linkman_alias;
		this.online_status = info.online_status;
		this.show_name = info.show_name;
	},
	parseJson:function(info) {
		this._init_(info)
	},
	getId:function() {
		return this.linkman_id;
	},
	getName:function() {
		return this.username;
	},
	getNickName:function() {
		return this.nick_name;
	},
	getLinkTime:function() {
		return this.link_time;
	},
	getHeadImg:function() {
		return this.avatar;
	},
	getAlias:function(){
		return this.linkman_alias;
	},
	getOnlineStatus:function() {
		return this.online_status;
	},
	getSex:function() {
		return this.sex;
	},
	getShowName:function() {
		return this.show_name;
	},
	setShowName:function(name) {
		this.show_name = name;
	}
}
function Group(info) {
	this._init_(info)
}
Group.prototype = {
	constructor:Group,
	_init_:function(info) {
		this.group_id = info.group_id;
		this.group_name = info.group_name;
		this.logo = info.logo;
		this.members = new List();
		if (info.members) {
			for(var m of info.members) {
				this.members.add(new GroupMember(m))
			}
		}
	},
	getGroupId:function() {
		return this.group_id;
	},
	getGroupName:function() {
		return this.group_name;
	},
	getGroupLogo:function() {
		return this.logo;
	},
	getGroupMembers:function() {
		return this.members;
	}
}
function GroupMember(info) {
	this._init_(info);
}
GroupMember.prototype = {
	constructor:GroupMember,
	_init_:function(info) {
		this.group_id = info.group_id;
		this.user_id = info.user_id;
		this.is_manager = info.is_manager;
		this.manager_level = info.manager_level;
		this.username = info.username;
		this.nick_name = info.nick_name;
		this.head_img = info.head_img;
		this.comment = info.comment;
	},
	getGroupId:function() {
		return this.group_id;
	},
	getUserId:function() {
		return this.user_id;
	},
	getIsManager:function() {
		return this.is_manager;
	},
	getManagerLevel:function() {
		return this.manager_level;
	},
	getUsername:function() {
		return this.username;
	},
	getNickName:function() {
		return this.nick_name;
	},
	getHeadImg:function() {
		return this.head_img;
	},
	getCommnet:function() {
		return this.comment;
	}
}
function ViewMessage(info) {
	this._init_(info);
}
ViewMessage.prototype = {
	constructor:ViewMessage,
	_init_:function(info) {
		this.version = info.version;
		this.from = info.from;
		this.to = info.to;
		this.time = info.time;
		this.content = info.content;
		this.avatar = info.avatar;
		this.nick_name = info.nick_name;
	},
	parseJson:function(info) {
		this._init_(info)
	},
	getVersion:function() {
		return this.version;
	},
	getFrom:function() {
		return this.from;
	},
	getTo:function() {
		return this.to;
	},
	getTime:function() {
		return this.time;
	},
	getContent:function() {
		return this.content;
	},
	getAvatar:function() {
		return this.avatar;
	},
	getNickName:function() {
		return nick_name;
	},
	setAvatar:function(a) {
		this.avatar = a;
	},
	setNickName:function(n) {
		this.nick_name = n;
	}
}

function Dialogue(info){
	this._init_(info);
}
Dialogue.prototype = {
	constructor:Dialogue,
	_init_:function(info) {
		this.type = info.type;
		this.id = info.id;
		this.nick_name = info.nick_name;
		this.link_time = info.link_time;
		this.avatar = info.avatar;
		this.quick_msg = info.quick_msg;
		this.hasnew = info.hasnew;
		this.show_time= info.show_time;
		this.is_active = info.is_active;
		this.msg_list = new List();
		if (info.msg_list) {
			for (var msg of info.msg_list) {
				this.msg_list.add(new ViewMessage(msg))
			}
		}
	},
	addMessage:function(msg) {
		this.link_time = msg.getTime();
		this.show_time = Utils.getShowTime(msg.getTime());
		if (msg.getContent.length > 10) {
			this.quick_msg = msg.getContent().substring(0,9) + '…';
		} else {
			this.quick_msg = msg.getContent().substring(0,10)
		}
		this.msg_list.add(msg);
	},
	setActive:function() {
		this.is_active = true;
	},
	setInactive:function() {
		this.is_active = false;
	},
	updateLinkTime:function() {
		this.link_time = Utils.formatDate(new Date().getTime());
		this.show_time = Utils.getShowTime(this.link_time);
	},
	getId:function() {
		return this.id;
	},
	getType:function() {
		return this.type;
	},
	setHasnew:function(state) {
		this.hasnew = state;
	}
}
function SyncMsgLatch(info) {
	this._init_(info);
}
SyncMsgLatch.prototype = {
	constructor:SyncMsgLatch,
	_init_:function(info) {
		this.id = info.id;
		this.lock = 0;
		this.list = new List();
	},
	getId:function() {
		return this.id;
	},
	getLock:function() {
		return this.lock;
	},
	setLock:function(value) {
		this.lock = value;
	},
	getList:function() {
		return this.list.getAll();
	},
	addMsg:function(msg) {
		this.list.add(msg);
	},
	clear:function() {
		this.list.removeAll();
	}
}
Vue.component('vue-scroll', vuescroll)
var vm = new Vue({
	el:"#app",
	data:{
		storage:{},
		base64:{},
		base_user_info:{head_img:'1',sex:0},
		g_link_list:new Map(),
		g_group_list:new Map(),
		g_msg_list:new Map(),
		sock:{},
		syncType:0,
		curMsgList:new List(),
		d_username:"",
		d_password:"",
		cur_dialogue:{},
		cur_linkman:{},
		cur_group:{members:{value:[]}},
		linkpage_content_type:0,
		linkman_page_title:'',
		page_tab:1,
		message:"",
		newMsg:false,
		syncMsgLatchList:new Map(),
		ops: {
			vuescroll: {},
			scrollPanel: {},
			rail: {
			  background: '#01a99a',
			  opacity: 0,
			  size: '10px',
			  specifyBorderRadius: false,
			  gutterOfEnds: null,    //轨道距 x 和 y 轴两端的距离
			  gutterOfSide: '0',   //距离容器的距离
			  keepShow: false,   //是否即使 bar 不存在的情况下也保持显示
			  border:'none'    //边框
			},
			bar: {
				hoverStyle: true,    
				onlyShowBarOnScroll: false, //是否只有滚动的时候才显示滚动条
				background: '#d2d2d2',   //颜色
			}
		},
	},
	methods:{
		dologin:function() {
			var _this = this;
			var deviceId = this.storage.getStr("_token");
			var ext = {device_id:deviceId,location:'北京',longitude:'116.404844',latitude:'39.913385'};
			//创建一个Request
			var msgRequest = new MsgRequest({type:0,username:this.d_username,password:this.d_password});
			msgRequest.setExt(ext);
			//请求的url：/user/login，方法：post
			//content-type：application/octet-stream
			this.postRequest("/user/login", msgRequest, data=>{
				var user = new UserInfo(data);
				//取本地记录的用户信息
				this.init(user);
				//创建websocket连接
				_this.createSocket();
				$('#dialog-login').modal('close');
			});
			
		},
		init:function(user) {
			this.g_link_list = new Map();
			this.g_group_list = new Map();
			this.g_msg_list = new Map();
			this.sock = {};
			this.syncType = 0;
			this.curMsgList = new List();
			this.cur_dialogue = {};
			this.cur_linkman = {};
			this.cur_group = {members:{value:[]}};
			this.linkpage_content_type = 0;
			this.linkman_page_title = '';
			this.page_tab = 1;
			this.message = "";
			this.newMsg = false;
			this.syncMsgLatchList = new Map();
			this.base_user_info = user;
			this.getGroupList();
			this.getLinkmansList();
		},
		getLinkmansList:function() {
			//取联系人列表
			var msgRequest = new MsgRequest({"user_id":this.base_user_info.getUserId()})
			var _this = this;
			this.postRequest("/linkman/list", msgRequest, data=>{
				for (var d of data) {
					var linkman = new LinkMan(d);
					linkman.setShowName(_this.getShowLinkManNick(linkman));
					_this.g_link_list.put(linkman.getId(), linkman);
				}
			});
		},
		getGroupList:function() {
			//取群列表
			var msgRequest = new MsgRequest({"user_id":this.base_user_info.getUserId()});
			var _this = this;
			this.postRequest("/group/list", msgRequest, data=>{
				for (var d of data) {
					var group = new Group(d);
					_this.g_group_list.put(group.getGroupId(), group);
				}
			});
		},
	    editorSetFocus:function() {
            this.$refs.msg_content.focus();
	    },
		createSocket:function() {
			this.sock = new WEBSOCKET(CONFIG._ws_base_url, this);
		},
		getShowLinkManNick:function(linkman) {
			var nick = linkman.getAlias();
			if (!nick) {
				nick = linkman.getNickName();
			}
			if (!nick) {
				nick = linkman.getName();
			}
			return nick;
		},
		convertMessage:function(msgMessage) {
			var viewMsg = new ViewMessage({
				version:msgMessage.getVersion(),
				from:msgMessage.getFrom(),
				to:msgMessage.getTo(),
				time:msgMessage.getTime(),
				content:this.base64.decode(msgMessage.getContent()),
				avatar:'',
				nick_name:msgMessage.getFrom()
			});
			var userId = msgMessage.getFrom();
			//当前用户
			if (userId == this.base_user_info.getUserId()) {
				viewMsg.setAvatar(this.base_user_info.getHeadImg());
				viewMsg.setNickName("我");
			} else {
				//从好友列表中查询
				var linkMan = this.g_link_list.get(userId);
				if (linkMan) {
					viewMsg.setAvatar(linkMan.getHeadImg());
					viewMsg.setNickName(linkMan.getShowName());
				} else {
					//从群成员列表中查询
					var groupId = msgMessage.getGroup();
					if ('0' != groupId) {
						var group = this.g_group_list.get(groupId);
						var memberList = group.getGroupMembers();
						if (memberList.size() == 0 ) {
							var latch = this.syncMsgLatchList.get(groupId);
							if (!latch) {
								latch = new SyncMsgLatch({id:groupId});
								this.syncMsgLatchList.put(groupId, latch);
							}
							if (latch.getLock() == 0) {
								
								//加锁
								latch.setLock(1);
								latch.addMsg(viewMsg);
								this.getGroupMemberList(groupId, mList=>{
									for (var msg of latch.getList()) {
										for (var mb of mList.getAll()) {
											if (mb.getUserId() == msg.getFrom()) {
												msg.setAvatar(mb.getHeadImg());
												msg.setNickName(mb.getNickName());
												break;
											}

										}
									}
									latch.clear();
									latch.setLock(0);
								})
							} else {
								latch.addMsg(viewMsg);
							}
						} else {
							for (var m of memberList.getAll()) {
								if (m.getUserId() == userId) {
									viewMsg.setAvatar(m.getHeadImg());
									viewMsg.setNickName(m.getNickName());
									break;
								}
							}
						}

					}
				}
			}
			return viewMsg;
		},
		getGroupMemberList:function(groupId, callback) {
			var groupInfo = this.g_group_list.get(groupId);
			var mList = groupInfo.getGroupMembers();
			var msgRequest = new MsgRequest({ext:{group_id:groupId}});
			this.postRequest('/group/member/list', msgRequest, data=>{
				for (var m of data) {
					var member = new GroupMember(m);
					mList.add(member);
				}
				if (callback) {
					callback(mList)
				}
			})
		},
		//向消息列表中添加消息
		addMessage:function(message, isNew) {
			var group = message.getGroup()
			var msgKey = ""
			var dialogue;
			if ('0' == group) {
				msgKey = message.getFrom();
				//自己发的消息
				if (msgKey == this.base_user_info.getUserId()) {
					msgKey = message.getTo();
				}
				dialogue = this.g_msg_list.get(msgKey);
				if (!dialogue) {
					var linkman = this.g_link_list.get(msgKey);
					dialogue = new Dialogue({
						type:'u',
						id:msgKey,
						nick_name:linkman.getShowName(),
						link_time:Utils.formatDate(new Date().getTime()),
						avatar:linkman.getHeadImg(),
						quick_msg:"",
						hasnew:false,
						is_active:false,
					});
					this.g_msg_list.put(msgKey, dialogue);
				}
			} else {
				msgKey = group;
				dialogue = this.g_msg_list.get(msgKey);
				if (!dialogue) {
					var groupInfo = this.g_group_list.get(msgKey);
					dialogue = new Dialogue({
						type:'g',
						id:msgKey,
						nick_name:groupInfo.getGroupName(),
						link_time:Utils.formatDate(new Date().getTime()),
						avatar:groupInfo.getGroupLogo(),
						quick_msg:"",
						hasnew:false,
						is_active:false,
					});
					this.g_msg_list.put(msgKey, dialogue);
				}
			}
			//向回话中添加消息
			dialogue.addMessage(this.convertMessage(message));
			if (isNew) {
				if (dialogue != this.cur_dialogue) {
					dialogue.setHasnew(true);
				}
				dialogue.updateLinkTime();
				//消息列表排序
				this.g_msg_list.sort('link_time');
				//回复确认消息
				var ack = new MsgMessage({
					type:"ack",
					from:this.base_user_info.getUserId(),
					to:"0",
					group:group,
					version:message.getVersion()
				});
				this.sock.doSend(ack.toByteArray());
			}
			
		},
		connection:function() {
			var message = new MsgMessage({
				type:'connection',
				version:0,
				time:Utils.formatDate(new Date().getTime()),
				from:this.base_user_info.getUserId(),
				to:'0',
				group:'0',
				token:this.base_user_info.getToken(),
			});
			this.sock.doSend(message.toByteArray());
			
		},
		sendHistoryMessage:function() {
			var message = new MsgMessage({
				type:'history',
				version:100,
				time:Utils.formatDate(new Date().getTime()),
				from:this.base_user_info.getUserId(),
				to:'0'
			});
			this.sock.doSend(message.toByteArray());
		},
		sendSyncMessage:function(groupId) {
			var message = new MsgMessage({
				type:'sync',
				version:0,
				time:Utils.formatDate(new Date().getTime()),
				from:this.base_user_info.getUserId(),
				to:'0',
				group:groupId
			});
			this.sock.doSend(message.toByteArray());
			this.syncType++;
		},
		showMessageList:function(id) {
			var lkmList = this.linkmans.values();
			for(var lkm in lkmList) {
				lkmList[lkm].active = false;
			}
			this.curLinkman = this.linkmans.get(id);
			this.curLinkman.active = true;
			this.curLinkman.hasnew = false;
			this.curMsgList = this.msgList.get(id);
		},
		
		postRequest:function(url, request, callback) {
			axios({
			    method: 'post',
			    url: CONFIG._api_base_url + url,
			    headers: {
			        'Content-type': 'application/octet-stream;charset=utf-8'
			    },
				data:request.toByteArray()
			}).then((response) => {
				if (response.status == 200) {
					var result = new MsgResult(response.data);
					if (result.getStatus() != 200) {
						alert('服务端返回错误：' + result.getMsg());
						return;
					}
					//正常业务逻辑
					callback(result.getDataObj());
				} else {
					console.log(response);					
				}
			}).catch((error) => {
			        console.log(error);
					alert(error.message)
			});
		},
		localStorageInit:function() {
			this.base64 = new Base64();
			var _this = this;
			this.storage.getStr = function (name) {
				var data = localStorage.getItem(name);
				if (data == undefined || data == null || data == '') {
					return '';
				}
				data = _this.base64.decode(data);
				return data;
			}
	
			this.storage.setStr = function (name, val) {
				if (val == undefined) val = '';
				localStorage.setItem(name, 
						_this.base64.encode(val));
			}
			
			this.storage.getObject = function (name) {
				var data = localStorage.getItem(name);
				if (data != undefined) {
					data = _this.base64.decode(data);
					return JSON.parse(data);
				}
				return undefined;
			}
	
			this.storage.setObject = function (name, obj) {
				localStorage.setItem(name, 
						_this.base64.encode(JSON.stringify(obj)));
			}
			this.storage.remove = function (name) {
				localStorage.removeItem(name);
			}
		},
		registerDevice:function() {
			var _token = this.storage.getStr("_token");
			if (_token) {
				return;	
			}
			_token = Utils.uuid();
			
			var msgDevice = new MsgDevice(
				{device_id:_token, 
				device_type:"web", 
				os:navigator.platform, 
				os_version:navigator.appVersion, 
				app_ver:"1.0"}
			);
			axios({
			    method: 'post',
			    url: CONFIG._api_base_url + '/device/register',
			    headers: {
			        'Content-type': 'application/octet-stream;charset=utf-8'
			    },
				data:msgDevice.toByteArray()
			}).then((response) => {
				var result = new MsgResult(response.data);
				if (result.getStatus() == 200) {
					this.storage.setStr("_token", _token);
					console.log("设备注册成功。")
				} else {
					console.log("设备注册失败：", result.getMsg());
				}
			})
			.catch(function(reason){
                console.log(reason);
            });
		},
		showGroupInfo:function(groupId) {
			this.cur_group = this.g_group_list.get(groupId);
			this.linkman_page_title = this.cur_group.getGroupName();
			if (this.cur_group.getGroupMembers().size() == 0) {
				this.getGroupMemberList(this.cur_group.getGroupId())
			}
			this.linkpage_content_type = 2;
		},
		showUserInfo:function(userId) {
			//设定当前用户
			this.cur_linkman = this.g_link_list.get(userId);
			this.linkman_page_title = this.cur_linkman.getShowName();
			this.linkpage_content_type = 1;
		},
		changeTab:function(e) {
			this.page_tab = e;
		},
		chatToLinkMan:function(linkManId) {
			if (this.cur_dialogue && this.cur_dialogue.setInactive) {
				this.cur_dialogue.setInactive();
			}
			this.cur_dialogue = this.g_msg_list.get(linkManId);
			if (this.cur_dialogue) {
				this.cur_dialogue.updateLinkTime();
				this.cur_dialogue.setActive();
			} else {
				var linkman = this.g_link_list.get(linkManId);
				this.cur_dialogue = new Dialogue({
					type:'u',
					id:linkManId,
					nick_name:linkman.getShowName(),
					link_time:Utils.formatDate(new Date().getTime()),
					avatar:linkman.getHeadImg(),
					quick_msg:"",
					hasnew:false,
					is_active:true
				});
				this.cur_dialogue.updateLinkTime();
				this.g_msg_list.put(linkManId, this.cur_dialogue);
			}
			this.g_msg_list.sort('link_time');
			//切换到聊天页面
			this.page_tab = 1;
		},
		chatToGroup:function(groupId) {
			if (this.cur_dialogue && this.cur_dialogue.setInactive) {
				this.cur_dialogue.setInactive();
			}
			this.cur_dialogue = this.g_msg_list.get(groupId);
			if (this.cur_dialogue) {
				this.cur_dialogue.updateLinkTime();
				this.cur_dialogue.setActive();
			} else {
				var group = this.g_group_list.get(groupId);
				this.cur_dialogue = new Dialogue({
					type:'g',
					id:groupId,
					nick_name:group.getGroupName(),
					link_time:Utils.formatDate(new Date().getTime()),
					avatar:group.getGroupLogo(),
					quick_msg:"",
					hasnew:false,
					is_active:true
				});
				this.cur_dialogue.updateLinkTime();
				this.g_msg_list.put(groupId, this.cur_dialogue);
			}
			this.g_msg_list.sort('link_time');
			//切换到聊天页面
			this.page_tab = 1;
		},
		showDialogueInfo:function(dialogueId) {
			if (this.cur_dialogue && this.cur_dialogue.setInactive) {
				this.cur_dialogue.setInactive();
			}
			this.cur_dialogue = this.g_msg_list.get(dialogueId);
			this.cur_dialogue.setActive();
			this.cur_dialogue.setHasnew(false);
		},
		sendMessage:function(){
			if (this.message == '' || this.message == '\n') {
				//在app中不弹出alert
				alert("Unable to send empty message");
				this.message = '';
				this.editorSetFocus();
				return;
			}
			if (!this.cur_dialogue.is_active) {
			    alert("Please select the recipient of the message");
			    this.message = '';
			    this.editorSetFocus();
			    return;
			}
			//创建消息对象
			var message = new MsgMessage({
				type:'message',
				version:0,
				time:Utils.formatDate(new Date().getTime()),
				from:this.base_user_info.getUserId(),
				to:this.cur_dialogue.getId(),
				group:this.cur_dialogue.getType() == 'u'?'0':this.cur_dialogue.getId(),
				token:this.base_user_info.getToken(),
				content_type:1,
				content:this.base64.encode(this.message)
			});
			this.sock.doSend(message.toByteArray());
			//添加消息到列表
			this.addMessage(message, false);
			//消息列表排序
			this.cur_dialogue.updateLinkTime();
			this.g_msg_list.sort('link_time');
			this.message = "";
		},
	},
	mounted:function() {
		zInit();
		//初始化localstorage
		this.localStorageInit();
		// 注册设备
		this.registerDevice();
		//打开登录窗口
		showLoginDialog();
	},
	//每次页面渲染完之后滚动条在最底部
	updated:function(){
		var _this=this;
		this.$nextTick(function(){
			_this.$refs.msg_list.scrollTo({y:'100%'},0)
		})
    }
});
